/*
 * $Id: ExchangeElementTests.m 249 2008-09-09 13:58:25Z jon $
 * Sleeper
 *
 * Created by Jon Gordon on 12/21/07
 * Copyright Jon Gordon.  All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to 
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#include <math.h>

#import "ExchangeElementTests.h"

#import "CallsignTests.h"

#import "QEExchangeElement.h"

@interface ExchangeElementTests (Private)
- (void)checkLegalFrequency:(QEExchangeElement *)element
                     source:(NSString *)source
              expectedValue:(double)expectedValue;
@end



@implementation ExchangeElementTests
- (void) testCreation
{
    [self checkSingletonosityForElement:@"call"];
    [self checkSingletonosityForElement:@"check"];
    [self checkSingletonosityForElement:@"freq"];
    [self checkSingletonosityForElement:@"prec"];
    [self checkSingletonosityForElement:@"section"];
    [self checkSingletonosityForElement:@"serialRcvd"];
} // testCreation

- (void)checkSingletonosityForElement:(NSString *)elementName
{
    QEExchangeElement *element1 = [QEExchangeElement elementForName:elementName];
    STAssertNotNil(element1, @"failed to retrieve instance of %@ element", elementName);
    STAssertEqualObjects(elementName, [element1 elementName], @"%@ element gives name as \"%@\"", elementName, [element1 elementName]);
    QEExchangeElement *element2 = [QEExchangeElement elementForName:elementName];
    STAssertNotNil(element2, @"failed on second try to retrieve instance of %@ element", elementName);
    STAssertEquals(element1, element2, @"multiple instances found for %@ element", elementName);
    STAssertEquals([element1 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    [element1 retain];
    STAssertEquals([element1 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    [element1 retain];
    STAssertEquals([element1 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    [element1 release];
    STAssertEquals([element1 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    QEExchangeElement *element3 = [QEExchangeElement elementForName:elementName];
    STAssertNotNil(element3, @"failed on third try to retrieve instance of %@ element", elementName);
    STAssertEquals(element1, element3, @"multiple instances found for %@ element", elementName);
    STAssertEquals([element3 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    [element1 retain];
    STAssertEquals([element3 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    [element1 release];
    STAssertEquals([element3 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
    [element1 release];
    STAssertEquals([element3 retainCount], UINT_MAX, @"incorrect retain count for %@ element", elementName);
} // checkSingletonosityForElement:

- (void)testCallsign
{
    NSLog(@"begin testCallsign");
    QEExchangeElement *element = [QEExchangeElement elementForName:@"call"];
    STAssertNotNil(element, @"failed to provide callsign element");
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid callsign element");
    
    NSArray *validCallsigns = listValidCallsigns();
    NSEnumerator *enumerator = [validCallsigns objectEnumerator];
    id callsign;
    while (callsign = [enumerator nextObject]) {
        STAssertTrue([element isLegalValueInString:callsign], @"failed to recognize \'%@\' as valid callsign", callsign);
    } // while
    NSLog(@"  end testCallsign");
} // testCallsign

- (void)testCallsignValues
{
    NSLog(@"begin testCallsignValues");
    QEExchangeElement *element = [QEExchangeElement elementForName:@"call"];
    STAssertNotNil(element, @"failed to provide callsign element");
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid callsign element");
    
    NSArray *validCallsigns = listValidCallsigns();
    NSEnumerator *enumerator = [validCallsigns objectEnumerator];
    id callsign;
    NSString * lower;
    while (callsign = [enumerator nextObject]) {
        lower = [callsign lowercaseString];
        STAssertEqualObjects(callsign,
                             [element valueForString:lower],
                             @"failed to convert callsign \"%@\" to \"%@\"");
    } // while
    NSLog(@"  end testCallsignValues");
} // testCallsignValues

- (void)testCheck
{
    QEExchangeElement *element = [QEExchangeElement elementForName:@"check"];
    STAssertNotNil(element, @"failed to provide check element");
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"7"], @"failed to reject invalid check element");
    STAssertTrue([element isLegalValueInString:@"00"], @"failed to accept valid check element");
    STAssertTrue([element isLegalValueInString:@"01"], @"failed to accept valid check element");
    STAssertTrue([element isLegalValueInString:@"99"], @"failed to accept valid check element");
    STAssertTrue([element isLegalValueInString:@"72"], @"failed to accept valid check element");
    STAssertFalse([element isLegalValueInString:@"0"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"000"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"999"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"321"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"042"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"10."], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"12.1"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"-10"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"-1"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"-032"], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"-032."], @"failed to reject invalid check element");
    STAssertFalse([element isLegalValueInString:@"-998"], @"failed to reject invalid check element");
}

- (void)testCheckValues
{
    NSArray *goodStrings = [NSArray arrayWithObjects: @"00", @"01", @"99", @"72", nil];
    NSArray *badStrings  = [NSArray arrayWithObjects:
                            @"", @"7", @"0", 
                            @"000", @"a3", @"999", 
                            @"-998", @"321", @"12.1", 
                            @"042", @"-10", @"-1", 
                            @"-032", @"-032.", @"10.", nil];
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"check"];
    STAssertNotNil(element, @"failed to provide check element");
    NSString *source;
    NSString *value;
    NSEnumerator *e = [goodStrings objectEnumerator];
    while (source = [e nextObject]) {
        value = [element valueForString:source];
        STAssertNotNil(value,
                       @"element \"%@\" incorrectly returned nil for valid value \"%@\"",
                       [element elementName],
                       source);
        STAssertEqualObjects(source,
                             value,
                             @"element \"%@\" incorrectly converted source \"%@\" to value \"%@\"",
                             [element elementName],
                             source,
                             value);
    } // while
    
    e = [badStrings objectEnumerator];
    while (source = [e nextObject]) {
        value = [element valueForString:source];
        STAssertNil(value,
                    @"element \"%@\" incorrectly converted invalid source \"%@\" to value \"%@\"",
                    [element elementName],
                    source,
                    value);
    } // while
} // testCheckValues

- (void)testFrequency
{
    QEExchangeElement *element = [QEExchangeElement elementForName:@"freq"];
    STAssertNotNil(element, @"failed to provide frequency element");
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid frequency");
    
    STAssertTrue([element isLegalValueInString:@"18"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"19"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"20"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"191"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"1.9"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"1900."], @"failed to accept valid frequency");
    
    STAssertTrue([element isLegalValueInString:@"3.6"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"36"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"3600"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"4.0"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"4"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"40"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"4000"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"371"], @"failed to accept valid frequency");
    
    STAssertTrue([element isLegalValueInString:@"7125"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"7.125"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"7125.5"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"73"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"7.3"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"7300"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"7.300"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"729"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"7295.5"], @"failed to accept valid frequency");
    
    STAssertTrue([element isLegalValueInString:@"1415"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14150"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14.15"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14150."], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14150.0"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"1435"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14350"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14.35"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14350."], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14350.0"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"1435000"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"142"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"14.20001"], @"failed to accept valid frequency");
    
    STAssertTrue([element isLegalValueInString:@"212"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21200"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21.2"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21.200"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21200.0"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"2145"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21450"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21.45"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21450"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21450."], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"2145000"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"2131"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"21.31001"], @"failed to accept valid frequency");
    
    STAssertTrue([element isLegalValueInString:@"283"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"28300"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"28.3"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"28300."], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"28300.0"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"297"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"29700"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"29.7"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"29700."], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"29700.0"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"297000"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"291"], @"failed to accept valid frequency");
    STAssertTrue([element isLegalValueInString:@"29.20001"], @"failed to accept valid frequency");
    
    STAssertFalse([element isLegalValueInString:@"35"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"7"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"14"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"21"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"28"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"14.300.1"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"-7175"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"arf"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"iliketrafficlights"], @"failed to reject invalid frequency");
    
    STAssertFalse([element isLegalValueInString:@"1.799"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"1799"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"2001"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"2.001"], @"failed to reject invalid frequency");
    
    STAssertFalse([element isLegalValueInString:@"3599999999"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"3.599"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"400000000001"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"4000.1"], @"failed to reject invalid frequency");
    
    STAssertFalse([element isLegalValueInString:@"7124"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"7124999."], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"7301"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"7.301"], @"failed to reject invalid frequency");
    
    STAssertFalse([element isLegalValueInString:@"14149"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"14149.999"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"14.3501"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"14350001"], @"failed to reject invalid frequency");
    
    STAssertFalse([element isLegalValueInString:@"21199999"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"21.199"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"21.451"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"2145000001"], @"failed to reject invalid frequency");
    
    STAssertFalse([element isLegalValueInString:@"28299"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"28299."], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"29700001"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"29.700001"], @"failed to reject invalid frequency");
    STAssertFalse([element isLegalValueInString:@"29700.001"], @"failed to reject invalid frequency");
    STAssertTrue([element isLegalValueInString:@"28700.001"], @"failed to accept valid frequency");
}

- (void)testFrequencyValues
{
    NSArray *badFrequencies = [NSArray arrayWithObjects:
                               @"", 
                               @"35", 
                               @"7", 
                               @"14", 
                               @"21", 
                               @"28", 
                               @"14.300.1", 
                               @"-7175", 
                               @"arf", 
                               @"iliketrafficlights", 
                               @"1.799", 
                               @"1799", 
                               @"2001", 
                               @"2.001", 
                               @"3599999999", 
                               @"3.599", 
                               @"400000000001", 
                               @"4000.1", 
                               @"7124",
                               @"7124999.",
                               @"7301",
                               @"7.301",
                               @"14149",
                               @"14149.999",
                               @"14.3501",
                               @"14350001",
                               @"21199999",
                               @"21.199",
                               @"21.451",
                               @"2145000001",
                               @"28299",
                               @"28299.",
                               @"29700001",
                               @"29.700001",
                               @"29700.001",
                               nil];
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"freq"];
    STAssertNotNil(element, @"failed to provide frequency element");    
    
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid frequency");
    
    [self checkLegalFrequency:element source:@"18" expectedValue:1.8];
    [self checkLegalFrequency:element source:@"19" expectedValue:1.9];
    [self checkLegalFrequency:element source:@"20" expectedValue:2.0];
    [self checkLegalFrequency:element source:@"191" expectedValue:1.91];
    [self checkLegalFrequency:element source:@"1.9" expectedValue:1.9];
    [self checkLegalFrequency:element source:@"1900." expectedValue:1.9];
    
    [self checkLegalFrequency:element source:@"3.6" expectedValue:3.6];
    [self checkLegalFrequency:element source:@"36" expectedValue:3.6];
    [self checkLegalFrequency:element source:@"3600" expectedValue:3.6];
    [self checkLegalFrequency:element source:@"4.0" expectedValue:4.0];
    [self checkLegalFrequency:element source:@"4" expectedValue:4.0];
    [self checkLegalFrequency:element source:@"40" expectedValue:4.0];
    [self checkLegalFrequency:element source:@"4000" expectedValue:4.0];
    [self checkLegalFrequency:element source:@"371" expectedValue:3.71];
    
    [self checkLegalFrequency:element source:@"7125" expectedValue:7.125];
    [self checkLegalFrequency:element source:@"7.125" expectedValue:7.125];
    [self checkLegalFrequency:element source:@"7125.5" expectedValue:7.1255];
    [self checkLegalFrequency:element source:@"73" expectedValue:7.3];
    [self checkLegalFrequency:element source:@"7.3" expectedValue:7.3];
    [self checkLegalFrequency:element source:@"7300" expectedValue:7.3];
    [self checkLegalFrequency:element source:@"7.300" expectedValue:7.3];
    [self checkLegalFrequency:element source:@"729" expectedValue:7.29];
    [self checkLegalFrequency:element source:@"7295.5" expectedValue:7.2955];
    
    [self checkLegalFrequency:element source:@"1415" expectedValue:14.15];
    [self checkLegalFrequency:element source:@"14150" expectedValue:14.15];
    [self checkLegalFrequency:element source:@"14.15" expectedValue:14.15];
    [self checkLegalFrequency:element source:@"14150." expectedValue:14.15];
    [self checkLegalFrequency:element source:@"14150.0" expectedValue:14.15];
    [self checkLegalFrequency:element source:@"1435" expectedValue:14.35];
    [self checkLegalFrequency:element source:@"14350" expectedValue:14.35];
    [self checkLegalFrequency:element source:@"14.35" expectedValue:14.35];
    [self checkLegalFrequency:element source:@"14350." expectedValue:14.35];
    [self checkLegalFrequency:element source:@"14350.0" expectedValue:14.35];
    [self checkLegalFrequency:element source:@"1435000" expectedValue:14.35];
    [self checkLegalFrequency:element source:@"142" expectedValue:14.2];
    [self checkLegalFrequency:element source:@"14.20001" expectedValue:14.20001];
    
    [self checkLegalFrequency:element source:@"212" expectedValue:21.2];
    [self checkLegalFrequency:element source:@"21200" expectedValue:21.2];
    [self checkLegalFrequency:element source:@"21.2" expectedValue:21.2];
    [self checkLegalFrequency:element source:@"21.200" expectedValue:21.2];
    [self checkLegalFrequency:element source:@"21200.2" expectedValue:21.2002];
    [self checkLegalFrequency:element source:@"2145" expectedValue:21.45];
    [self checkLegalFrequency:element source:@"21450" expectedValue:21.45];
    [self checkLegalFrequency:element source:@"21.45" expectedValue:21.45];
    [self checkLegalFrequency:element source:@"21450." expectedValue:21.45];
    [self checkLegalFrequency:element source:@"21450.0" expectedValue:21.45];
    [self checkLegalFrequency:element source:@"2145000" expectedValue:21.45];
    [self checkLegalFrequency:element source:@"2131" expectedValue:21.31];
    [self checkLegalFrequency:element source:@"21.31001" expectedValue:21.31001];
    
    [self checkLegalFrequency:element source:@"283" expectedValue:28.3];
    [self checkLegalFrequency:element source:@"28300" expectedValue:28.3];
    [self checkLegalFrequency:element source:@"28.3" expectedValue:28.3];
    [self checkLegalFrequency:element source:@"28300." expectedValue:28.3];
    [self checkLegalFrequency:element source:@"28300.0" expectedValue:28.3];
    [self checkLegalFrequency:element source:@"297" expectedValue:29.7];
    [self checkLegalFrequency:element source:@"29700" expectedValue:29.7];
    [self checkLegalFrequency:element source:@"29.7" expectedValue:29.7];
    [self checkLegalFrequency:element source:@"29700." expectedValue:29.7];
    [self checkLegalFrequency:element source:@"29700.0" expectedValue:29.7];
    [self checkLegalFrequency:element source:@"297000" expectedValue:29.7];
    [self checkLegalFrequency:element source:@"291" expectedValue:29.1];
    [self checkLegalFrequency:element source:@"29.20001" expectedValue:29.20001];
    
    NSString *source;
    NSNumber *value;
    NSEnumerator *e = [badFrequencies objectEnumerator];
    while (source = [e nextObject]) {
        value = [element valueForString:source];
        STAssertNil(value, 
                    @"element \"%@\" incorrectly interpreted invalid source \"%@\" as value %@",
                    [element elementName],
                    source,
                    value);
    } // while
    
    STAssertTrue([element isLegalValueInString:@"28700.001"], @"failed to accept valid frequency");
} // testFrequencyValues


- (void) checkLegalFrequency:(QEExchangeElement *)element
                      source:(NSString *)source
               expectedValue:(double)expectedValue;

{
    NSNumber *value = [element valueForString:source];
    NSNumber *expectedValueAsObject;
    double difference;
    
    STAssertNotNil(value, @"failed to provide value for legal source \"%@\"", source);
    if (nil != value) {
        expectedValueAsObject = [NSNumber numberWithDouble:expectedValue];
        difference = fabs([expectedValueAsObject doubleValue] - [value doubleValue]);
        STAssertTrue((difference == 0),
                     @"failed to return proper frequency for source \"%@\"; expected %@; got %@ (difference is %@)",
                     source,
                     expectedValueAsObject,
                     value,
                     [NSNumber numberWithDouble:difference]);
    } // if
} // checkLegalFrequency(QEExchangeElement *, NSString *, double)


- (void)testPrecedence
{
    NSArray *goodSources = [NSArray arrayWithObjects:
                            @"q",
                            @"Q",
                            @"a",
                            @"A",
                            @"b",
                            @"B",
                            @"m",
                            @"M",
                            @"u",
                            @"U",
                            @"s",
                            @"S",
                            nil];
    NSArray *badSources  = [NSArray arrayWithObjects:
                            @"xF",
                            @"abcdefghijkolmpndadsy",
                            @"^&-",
                            @"v",
                            @",\"--",
                            @"aa",
                            @"uu",
                            @"dgbijgwwv",
                            nil];
    
    NSString *source;
    NSEnumerator *sources;
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"prec"];
    STAssertNotNil(element, @"failed to provide precedence element");
    
    STAssertFalse([element isLegalValueInString:@""], @"improperly accepted invalid precedence");
    STAssertFalse([element isLegalValueInString:@"2"], @"improperly accepted invalid precedence");
    
    sources = [goodSources objectEnumerator];
    while (source = [sources nextObject]) {
        STAssertTrue([element isLegalValueInString:source], @"failed to recognize valid precedence \"%@\"", source);
    } // while
    
    sources = [badSources objectEnumerator];
    while (source = [sources nextObject]) {
        STAssertFalse([element isLegalValueInString:source], @"improperly accepted invalid precedence \"%@\"", source);
    } // while
    
    STAssertTrue([element isLegalValueInString:@"q"], @"failed to recognize valid precedence");
    STAssertTrue([element isLegalValueInString:@"Q"], @"failed to recognize valid precedence");
} // testPrecedence


- (void)testPrecedenceValues
{
    NSArray *goodSources = [NSArray arrayWithObjects:
                            @"q",
                            @"Q",
                            @"a",
                            @"A",
                            @"b",
                            @"B",
                            @"m",
                            @"M",
                            @"u",
                            @"U",
                            @"s",
                            @"S",
                            nil];
    NSArray *badSources  = [NSArray arrayWithObjects:
                            @"xF",
                            @"abcdefghijkolmpndadsy",
                            @"^&-",
                            @"v",
                            @",\"--",
                            @"aa",
                            @"uu",
                            @"dgbijgwwv",
                            nil];
    
    NSString *source;
    NSString *value;
    NSEnumerator *sources;
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"prec"];
    STAssertNotNil(element, @"failed to provide precedence element");
    STAssertFalse([element isLegalValueInString:@""], @"improperly accepted invalid precedence");
    STAssertFalse([element isLegalValueInString:@"2"], @"improperly accepted invalid precedence");
    
    sources = [goodSources objectEnumerator];
    while (source = [sources nextObject]) {
        value = [element valueForString:source];
        STAssertNotNil(value, @"failed to recognize valid precedence \"%@\"", source);
        if (nil != value) {
            STAssertEqualObjects([source uppercaseString],
                                 value,
                                 @"returned incorrect precedence \"%@\" for source \"%@\"",
                                 value,
                                 source);
        } // if
    } // while
    
    sources = [badSources objectEnumerator];
    while (source = [sources nextObject]) {
        value = [element valueForString:source];
        STAssertNil(value, @"improperly gave value \"%@\" for invalid source \"%@\"", value, source);
    } // while
} // testPrecedenceValues


- (void)testSection
{
    // ARRL/RAC sections, included in November Sweepstakes exchange
    NSArray *sections = [[NSArray alloc] initWithObjects:@"CT", @"EMA", @"ME", @"NH", @"RI", @"VT", @"WMA",
                         @"ENY", @"NLI", @"NNJ", @"NNY", @"SNJ", @"WNY",
                         @"DE", @"EPA", @"MDC", @"WPA",
                         @"AL", @"GA", @"KY", @"NC", @"NFL", @"SC", @"SFL", @"WCF", @"TN", @"VA", @"PR", @"VI",
                         @"AR", @"LA", @"MS", @"NM", @"NTX", @"OK", @"STX", @"WTX",
                         @"EB", @"LAX", @"ORG", @"SB", @"SCV", @"SDG", @"SF", @"SJV", @"SV", @"PAC",
                         @"AZ", @"EWA", @"ID", @"MT", @"NV", @"OR", @"UT", @"WWA", @"WY", @"AK",
                         @"MI", @"OH", @"WV",
                         @"IL", @"IN", @"WI",
                         @"CO", @"IA", @"KS", @"MN", @"MO", @"NE", @"ND", @"SD",
                         @"MAR", @"NL", @"QC", @"ON", @"MB", @"SK", @"AB", @"BC", @"NT",
                         nil];
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"section"];
    STAssertNotNil(element, @"failed to provide section element");
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid section");
    STAssertFalse([element isLegalValueInString:@"WX"], @"failed to reject invalid section");
    
    NSEnumerator *enumerator = [sections objectEnumerator];
    id section;
    while (section = [enumerator nextObject]) {
        STAssertTrue([element isLegalValueInString:section], @"failed to recognize \'%@\' as valid section", section);
    } // while
    
    STAssertFalse([element isLegalValueInString:@"5r"], @"failed to reject invalid section");
    STAssertFalse([element isLegalValueInString:@"xxx"], @"failed to reject invalid section");
    STAssertFalse([element isLegalValueInString:@"mynameislarry43"], @"failed to reject invalid section");
    STAssertFalse([element isLegalValueInString:@"ER"], @"failed to reject invalid section");
    STAssertFalse([element isLegalValueInString:@"CA"], @"failed to reject invalid section");
    
    [sections release];
} // testSection


- (void)testSectionValues
{
    // ARRL/RAC sections, included in November Sweepstakes exchange
    NSArray *goodSections = [NSArray arrayWithObjects:@"CT", @"EMA", @"ME", @"NH", @"RI", @"VT", @"WMA",
                             @"ENY", @"NLI", @"NNJ", @"NNY", @"SNJ", @"WNY",
                             @"DE", @"EPA", @"MDC", @"WPA",
                             @"AL", @"GA", @"KY", @"NC", @"NFL", @"SC", @"SFL", @"WCF", @"TN", @"VA", @"PR", @"VI",
                             @"AR", @"LA", @"MS", @"NM", @"NTX", @"OK", @"STX", @"WTX",
                             @"EB", @"LAX", @"ORG", @"SB", @"SCV", @"SDG", @"SF", @"SJV", @"SV", @"PAC",
                             @"AZ", @"EWA", @"ID", @"MT", @"NV", @"OR", @"UT", @"WWA", @"WY", @"AK",
                             @"MI", @"OH", @"WV",
                             @"IL", @"IN", @"WI",
                             @"CO", @"IA", @"KS", @"MN", @"MO", @"NE", @"ND", @"SD",
                             @"MAR", @"NL", @"QC", @"ON", @"MB", @"SK", @"AB", @"BC", @"NT",
                             nil];
    NSArray *badSections = [NSArray arrayWithObjects:@"5r", @"xxx", @"mynameislarry43", @"ER", @"CA", nil];
    NSEnumerator *sources;
    NSString *source;
    NSString *value;
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"section"];
    STAssertNotNil(element, @"failed to provide section element");
    
    STAssertFalse([element isLegalValueInString:@""], @"failed to reject invalid section");
    STAssertFalse([element isLegalValueInString:@"WX"], @"failed to reject invalid section");
    
    sources = [goodSections objectEnumerator];
    while (source = [sources nextObject]) {
        value = [element valueForString:source];
        STAssertNotNil(value, @"failed to provide section for valid source \"%@\"", source);
        if (nil != value) {
            STAssertEqualObjects(source, 
                                 value, 
                                 @"incorrectly gave value of \"%@\" for source \"%@\"",
                                 value,
                                 source);
        } // if
    } // while
    
    sources = [goodSections objectEnumerator];
    while (source = [sources nextObject]) {
        source = [source lowercaseString];
        value = [element valueForString:source];
        STAssertNotNil(value, @"failed to provide section for valid source \"%@\"", source);
        if (nil != value) {
            STAssertEqualObjects([source uppercaseString], 
                                 value, 
                                 @"incorrectly gave value of \"%@\" for source \"%@\"",
                                 value,
                                 source);
        } // if
    } // while
    
    sources = [badSections objectEnumerator];
    while (source = [sources nextObject]) {
        value = [element valueForString:source];
        STAssertNil(value, 
                    @"failed to reject invalid section \"%@\", returned \"%@\"", 
                    source,
                    value);
    } // while
} // testSectionValues


- (void)testSerial
{
    NSArray *goodSerials = [NSArray arrayWithObjects:
                            @"1",
                            @"999",
                            @"3599",
                            @"3598",
                            @"2",
                            @"n50",
                            @"N55",
                            @"Nr761",
                            @"nR3599",
                            @"NR1",
                            nil];
    NSArray *badSerials = [NSArray arrayWithObjects:
                           @"-1",
                           @"-99",
                           @"3600",
                           @"r100",
                           @"R201",
                           @"201.",
                           @"r50",
                           @"NR50.0",
                           nil];

    NSEnumerator *sources;
    NSString *source;
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"serialRcvd"];
    STAssertNotNil(element, @"failed to provide serial element");
    STAssertFalse([element isLegalValueInString:@""], @"improperly accepted invalid serial");
    STAssertFalse([element isLegalValueInString:@"0"], @"improperly accepted invalid serial");
    
    sources = [goodSerials objectEnumerator];
    while (source = [sources nextObject]) {
        STAssertTrue([element isLegalValueInString:source], @"failed to recognize valid serial \"%@\"", source);
    } // while
    
    sources = [badSerials objectEnumerator];
    while (source = [sources nextObject]) {
        STAssertFalse([element isLegalValueInString:source], @"improperly accepted invalid serial \"%@\"", source);
    } // while
} // // testSerial()


- (void)testSerialValues
{
    NSArray *goodSerials = [NSArray arrayWithObjects:
                            @"1",
                            @"999",
                            @"3599",
                            @"3598",
                            @"2",
                            @"n50",
                            @"N55",
                            @"Nr761",
                            @"nR3599",
                            @"NR1",
                            nil];
    NSArray *expectedSerialValues = [NSArray arrayWithObjects:
                                     [NSNumber numberWithInt:1],
                                     [NSNumber numberWithInt:999],
                                     [NSNumber numberWithInt:3599],
                                     [NSNumber numberWithInt:3598],
                                     [NSNumber numberWithInt:2],
                                     [NSNumber numberWithInt:50],
                                     [NSNumber numberWithInt:55],
                                     [NSNumber numberWithInt:761],
                                     [NSNumber numberWithInt:3599],
                                     [NSNumber numberWithInt:1],
                                     nil];
    NSArray *badSerials = [NSArray arrayWithObjects:
                           @"-1",
                           @"-99",
                           @"3600",
                           @"r100",
                           @"R201",
                           @"201.",
                           @"r50",
                           @"NR50.0",
                           nil];
    
    NSEnumerator *sources;
    NSString *source;
    NSNumber *value;
    NSEnumerator *expectedValues;
    NSNumber *expectedValue;
    
    QEExchangeElement *element = [QEExchangeElement elementForName:@"serialRcvd"];
    STAssertNotNil(element, @"failed to provide serial element");
    STAssertFalse([element isLegalValueInString:@""], @"improperly accepted invalid serial");
    STAssertFalse([element isLegalValueInString:@"0"], @"improperly accepted invalid serial");
    
    sources = [goodSerials objectEnumerator];
    expectedValues = [expectedSerialValues objectEnumerator];
    while (source = [sources nextObject]) {
        expectedValue = [expectedValues nextObject];
        value = [element valueForString:source];
        STAssertNotNil(value, @"failed to give value for valid serial \"%@\"", source);
        if (nil != value) {
            STAssertEqualObjects(value,
                                 expectedValue,
                                 @"valid serial \"%@\" incorrectly interpreted as value %@",
                                 source,
                                 value);
        } // if
        STAssertTrue([element isLegalValueInString:source], @"failed to recognize valid serial \"%@\"", source);
    } // while
    
    sources = [badSerials objectEnumerator];
    while (source = [sources nextObject]) {
        value = [element valueForString:source];
        STAssertNil(value,
                    @"improperly gave value \"%@\" for invalid serial \"%@\"", 
                    value,
                    source);
    } // while
} // testSerialValues()
@end